/* Copyright (c) 2009-2010, Sean A.O. Harney <sharney3@gmail.com> */

#include "omf.h"


bool builtin_funcs_init(void)
{
    builtin_funcs_add_unary("hd", &builtin_func_hd);
    builtin_funcs_add_unary("tl", &builtin_func_tl);
    builtin_funcs_add_unary("sleep", &builtin_func_sleep);
    builtin_funcs_add_unary("eval", &builtin_func_eval);

    builtin_funcs_add_binary("open", &builtin_func_open);
    builtin_funcs_add_unary("flush", &builtin_func_flush);
    builtin_funcs_add_unary("close", &builtin_func_close);
    builtin_funcs_add_binary("write", &builtin_func_write);
    builtin_funcs_add_binary("read", &builtin_func_read);

    return true;
}

void builtin_funcs_add_void(char *funcname, BUILTIN_FUNC_VOID_P func_ptr)
{
    BUILTIN_FUNC_P builtin_func =
	checked_malloc(sizeof(struct st_builtin_func));

    builtin_func->arity = 0;
    builtin_func->funcp.funcp_void = func_ptr;

    if (!symbol_tbl_new_entry_function_builtin(funcname, builtin_func))
	fatal_error_println("add_builtin_func_void() failed");
}

void builtin_funcs_add_unary(char *funcname, BUILTIN_FUNC_UNARY_P func_ptr)
{
    BUILTIN_FUNC_P builtin_func =
	checked_malloc(sizeof(struct st_builtin_func));

    builtin_func->arity = 1;
    builtin_func->funcp.funcp_unary = func_ptr;

    if (!symbol_tbl_new_entry_function_builtin(funcname, builtin_func))
	fatal_error_println("add_builtin_func_unary() failed");
}

void builtin_funcs_add_binary(char *funcname,
			      BUILTIN_FUNC_BINARY_P func_ptr)
{
    BUILTIN_FUNC_P builtin_func =
	checked_malloc(sizeof(struct st_builtin_func));

    builtin_func->arity = 2;
    builtin_func->funcp.funcp_binary = func_ptr;

    if (!symbol_tbl_new_entry_function_builtin(funcname, builtin_func))
	fatal_error_println("add_builtin_func_binary() failed");
}

void builtin_funcs_add_trinary(char *funcname,
			       BUILTIN_FUNC_TRINARY_P func_ptr)
{
    BUILTIN_FUNC_P builtin_func =
	checked_malloc(sizeof(struct st_builtin_func));

    builtin_func->arity = 3;
    builtin_func->funcp.funcp_trinary = func_ptr;

    if (!symbol_tbl_new_entry_function_builtin(funcname, builtin_func))
	fatal_error_println("add_builtin_func_trinary() failed");
}

//Args length is expected to equal builtin_func->arity.
//TODO: perhaps make args end with NULL element so its size known and assert this.
EXPR_P builtin_funcs_invoke(BUILTIN_FUNC_P builtin_func, EXPR_P args[])
{
    switch (builtin_func->arity)
      {
      case 0:
	  return builtin_func->funcp.funcp_void();
      case 1:
	  return builtin_func->funcp.funcp_unary(args[0]);
      case 2:
	  return builtin_func->funcp.funcp_binary(args[0], args[1]);
      case 3:
	  return builtin_func->funcp.funcp_trinary(args[0], args[1],
						   args[2]);
      default:
	  error_println("builtin_function_invoke(): invalid function arity\n");	// shouldn't happen
	  return NULL;
      }
}
